﻿using Microsoft.Extensions.Caching.Distributed;
using Polaris.Common.ExtensionMethod;
using Polaris.Domain.Model.Enum;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Polaris.Common.RedisHelper
{
    public class CacheRedisHelper : ICacheRedis
    {

        readonly IDistributedCache _cache;

        public CacheRedisHelper(IDistributedCache cache)
        {
            _cache = cache;
        }

        protected string BuildKey(string idKey)
        {
            return $"Cache_{idKey}";
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public void SetCache(string key, object value)
        {
            string cacheKey = BuildKey(key);
            _cache.SetString(cacheKey, value.ToJson());
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <param name="value">值</param>
        public async Task SetCacheAsync(string key, object value)
        {
            string cacheKey = BuildKey(key);
            await _cache.SetStringAsync(cacheKey, value.ToJson());
        }

        /// <summary>
        /// 设置缓存
        /// 注：默认过期类型为绝对过期
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <param name="value">值</param>
        /// <param name="minutes">过期时间间隔 以分钟为单位</param>
        public void SetCache(string key, object value, int minutes)
        {
            string cacheKey = BuildKey(key);
            _cache.SetString(cacheKey, value.ToJson(), new DistributedCacheEntryOptions
            {
                AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(minutes)
            });
        }

        /// <summary>
        /// 设置缓存
        /// 注：默认过期类型为绝对过期
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <param name="value">值</param>
        /// <param name="timeout">过期时间间隔 以分钟为单位</param>
        public async Task SetCacheAsync(string key, object value, int minutes)
        {
            string cacheKey = BuildKey(key);
            await _cache.SetStringAsync(cacheKey, value.ToJson(), new DistributedCacheEntryOptions
            {
                AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(minutes)
            });
        }

        /// <summary>
        /// 设置缓存
        /// 注：默认过期类型为绝对过期
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <param name="value">值</param>
        /// <param name="minutes">过期时间间隔 以分钟为单位</param>
        /// <param name="expireType">过期类型</param>  
        public void SetCache(string key, object value, int minutes, ExpireType expireType)
        {
            string cacheKey = BuildKey(key);
            if (expireType == ExpireType.Absolute)
            {
                //这里没转换标准时间，Linux时区会有问题？
                _cache.SetString(cacheKey, value.ToJson(), new DistributedCacheEntryOptions
                {
                    AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(minutes)
                });
            }
            else
            {
                _cache.SetString(cacheKey, value.ToJson(), new DistributedCacheEntryOptions
                {
                    AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(minutes)
                });
            }
        }

        /// <summary>
        /// 设置缓存
        /// 注：默认过期类型为绝对过期
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <param name="value">值</param>
        /// <param name="minutes">过期时间间隔 以分钟为单位</param>
        /// <param name="expireType">过期类型</param>  
        public async Task SetCacheAsync(string key, object value, int minutes, ExpireType expireType)
        {
            string cacheKey = BuildKey(key);
            if (expireType == ExpireType.Absolute)
            {
                //这里没转换标准时间，Linux时区会有问题？
                await _cache.SetStringAsync(cacheKey, value.ToJson(), new DistributedCacheEntryOptions
                {
                    AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(minutes)
                });
            }
            else
            {
                await _cache.SetStringAsync(cacheKey, value.ToJson(), new DistributedCacheEntryOptions
                {
                    AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(minutes)
                });
            }
        }

        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <param name="key">缓存Key</param>
        public string GetCache(string idKey)
        {
            if (string.IsNullOrEmpty(idKey))
            {
                return null;
            }
            string cacheKey = BuildKey(idKey);
            var cache = _cache.GetString(cacheKey);
            return cache;
        }

        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <param name="key">缓存Key</param>
        public async Task<string> GetCacheAsync(string key)
        {
            if (string.IsNullOrEmpty(key))
            {
                return null;
            }
            string cacheKey = BuildKey(key);
            var cache = await _cache.GetStringAsync(cacheKey);
            return cache;
        }

        /// <summary>
        /// 获取缓存,没有则添加
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="minutes"></param>
        /// <param name="expireType">过期类型，默认绝对过期</param>
        /// <returns></returns>
        public async Task<string> GetOrAddAsync(string key, object value, int minutes, ExpireType expireType = 0)
        {
            if (string.IsNullOrEmpty(key)) return null;

            string cacheKey = BuildKey(key);
            var cache = await _cache.GetStringAsync(cacheKey);
            if (cache == null)
            {
                string json = value.ToJson();
                if (expireType == ExpireType.Absolute)
                {
                    //这里没转换标准时间，Linux时区会有问题？
                    await _cache.SetStringAsync(cacheKey, json, new DistributedCacheEntryOptions
                    {
                        AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(minutes)
                    });
                }
                else
                {
                    await _cache.SetStringAsync(cacheKey, json, new DistributedCacheEntryOptions
                    {
                        AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(minutes)
                    });
                }
                return json;
            }
            return cache;
        }

        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <param name="key">缓存Key</param>
        public T GetCache<T>(string key)
        {
            var cache = GetCache(key);
            if (!string.IsNullOrEmpty(cache))
            {
                return cache.ToObject<T>();
            }
            return default(T);
        }

        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <param name="key">缓存Key</param>
        public async Task<T> GetCacheAsync<T>(string key)
        {
            var cache = await GetCacheAsync(key);
            if (!string.IsNullOrEmpty(cache))
            {
                return cache.ToObject<T>();
            }
            return default(T);
        }

        /// <summary>
        /// 获取泛型缓存,没有则添加
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="minutes"></param>
        /// <param name="expireType">过期类型，默认绝对过期</param>
        /// <returns></returns>
        public async Task<T> GetOrAddAsync<T>(string key, Func<Task<T>> valueFactory, int minutes, ExpireType expireType = 0)
        {
            if (string.IsNullOrEmpty(key)) return default(T);

            string cacheKey = BuildKey(key);
            var cache = await _cache.GetStringAsync(cacheKey);

            if (cache == null)
            {//缓存中没有数据去查实际的数据
                T value = await valueFactory();
                string json = value.ToJson();
                //如果查实际的数据还是没有那么直接返回空
                if (string.IsNullOrWhiteSpace(json)) return cache.ToObject<T>();

                if (expireType == ExpireType.Absolute)
                {
                    //这里没转换标准时间，Linux时区会有问题？
                    await _cache.SetStringAsync(cacheKey, json, new DistributedCacheEntryOptions
                    {
                        AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(minutes)
                    });
                }
                else
                {
                    await _cache.SetStringAsync(cacheKey, json, new DistributedCacheEntryOptions
                    {
                        AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(minutes)
                    });
                }
                return json.ToObject<T>();
            }
            return cache.ToObject<T>();
        }

        /// <summary>
        /// 获取泛型集合缓存,没有则添加
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="valueFactory"></param>
        /// <param name="minutes"></param>
        /// <param name="expireType"></param>
        /// <returns></returns>
        public async Task<List<T>> GetOrAddListAsync<T>(string key, Func<Task<List<T>>> valueFactory, int minutes, ExpireType expireType = 0)
        {
            if (string.IsNullOrEmpty(key)) return default(List<T>);

            string cacheKey = BuildKey(key);
            var cache = await _cache.GetStringAsync(cacheKey);

            if (cache == null)
            {//缓存中没有数据去查实际的数据
                List<T> value = await valueFactory();
                string json = value.ToJson();
                //如果查实际的数据还是没有那么直接返回空
                if (string.IsNullOrWhiteSpace(json)) return cache.ToObject<List<T>>();

                if (expireType == ExpireType.Absolute)
                {
                    //这里没转换标准时间，Linux时区会有问题？
                    await _cache.SetStringAsync(cacheKey, json, new DistributedCacheEntryOptions
                    {
                        AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(minutes)
                    });
                }
                else
                {
                    await _cache.SetStringAsync(cacheKey, json, new DistributedCacheEntryOptions
                    {
                        AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(minutes)
                    });
                }
                return json.ToObject<List<T>>();
            }
            return cache.ToObject<List<T>>();
        }

        /// <summary>
        /// 清除缓存
        /// </summary>
        /// <param name="key">缓存Key</param>
        public void RemoveCache(string key)
        {
            _cache.Remove(BuildKey(key));
        }

        /// <summary>
        /// 清除缓存 异步
        /// </summary>
        /// <param name="key">缓存Key</param>
        public async Task RemoveCacheAsync(string key)
        {
            await _cache.RemoveAsync(BuildKey(key));
        }

        /// <summary>
        /// 刷新缓存
        /// </summary>
        /// <param name="key">缓存Key</param>
        public void RefreshCache(string key)
        {
            _cache.Refresh(BuildKey(key));
        }

        /// <summary>
        /// 刷新缓存 异步
        /// </summary>
        /// <param name="key">缓存Key</param>
        public async Task RefreshCacheAsync(string key)
        {
            await _cache.RefreshAsync(BuildKey(key));
        }


    }
}
